package com.wicket.okrbff.plugin.aop;


import cn.hutool.core.bean.BeanUtil;
import com.wicket.okrbff.common.baseinfo.BaseInfoDO;
import com.wicket.okrbff.common.baseinfo.BaseInfoHolder;
import com.wicket.okrbff.common.dto.MetaDataDto;
import com.wicket.okrbff.common.exception.BizException;
import com.wicket.okrbff.common.util.MetaDataHelper;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.data.repository.query.DefaultParameters;
import org.springframework.data.repository.query.Parameter;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.List;

/**
 * 切入feign方法，设置基本信息
 * @author CHS
 * @since 2022/4/5 19:52
 * @version 1.0
 **/
@Component
@Aspect
@Slf4j
public class ClientBaseInfoAspect {

    @Pointcut("execution(* com.wicket.okrframework.integration.*.*(..)) || execution(* com.wicket.okrcomponent.integration.*.*(..)) || execution(* com.wicket.okrapp.integration.*.*(..)) || execution(* com.wicket.okrcalc.integration.*.*(..)) || execution(* com.wicket.okrfinance.integration.*.*(..)) || execution(* com.wicket.okrdataassets.integration.*.*(..))")
    public void feignPointcut() {
    }

    @Before("feignPointcut()")
    public void before(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        if (args[0] instanceof com.wicket.okrframework.common.dto.BaseDto
                || args[0] instanceof com.wicket.okrcomponent.common.dto.BaseDto
                || args[0] instanceof com.wicket.okrapp.common.dto.BaseDto
                || args[0] instanceof com.wicket.okrcalc.common.dto.BaseDto
                || args[0] instanceof com.wicket.okrfinance.common.dto.BaseDto
                || args[0] instanceof com.wicket.okrdataassets.common.dto.BaseDto) {
            Object target = args[0];
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            List<Parameter> parameters = new DefaultParameters(methodSignature.getMethod()).toList();
            try {
                for (int i = 0; i < parameters.size(); i++) {
                    Parameter parameter = parameters.get(i);
                    if (BaseInfoHolder.contextHolder == null) continue;
                    if (BaseInfoHolder.contextHolder.get() == null) continue;
                    BaseInfoDO baseInfoDO = BaseInfoHolder.contextHolder.get().getBaseInfo();
                    if (com.wicket.okrframework.common.dto.BaseDto.class.isAssignableFrom(parameter.getType())
                            || com.wicket.okrcomponent.common.dto.BaseDto.class.isAssignableFrom(parameter.getType())
                            || com.wicket.okrapp.common.dto.BaseDto.class.isAssignableFrom(parameter.getType())
                            || com.wicket.okrcalc.common.dto.BaseDto.class.isAssignableFrom(parameter.getType())
                            || com.wicket.okrfinance.common.dto.BaseDto.class.isAssignableFrom(parameter.getType())
                            || com.wicket.okrdataassets.common.dto.BaseDto.class.isAssignableFrom(parameter.getType())) {

                        BeanUtil.copyProperties(baseInfoDO, target);
                    }
                }
            } catch (Exception e) {
                log.error("method: {} set basic info error", methodSignature.getMethod().getName(), e);
            }
        }

    }

    @AfterReturning(returning = "ret", pointcut = "feignPointcut()")
    public void dealRetData(JoinPoint joinPoint, Object ret) throws Exception {
        if (ret instanceof com.wicket.okrframework.common.ro.OkrResult<?>) {
            com.wicket.okrframework.common.ro.OkrResult<?> result = (com.wicket.okrframework.common.ro.OkrResult<?>) ret;
            if (result.getMessage() != null && !result.getMessage().isEmpty()) {
                throw new BizException(result.getErrCode(), result.getMessage(), false);
            }
        } else if (ret instanceof com.wicket.okrcomponent.common.ro.OkrResult<?>) {
            com.wicket.okrcomponent.common.ro.OkrResult<?> result = (com.wicket.okrcomponent.common.ro.OkrResult<?>) ret;
            if (result.getMessage() != null && !result.getMessage().isEmpty()) {
                throw new BizException(result.getErrCode(), result.getMessage(), false);
            }
        } else if (ret instanceof com.wicket.okrapp.common.ro.OkrResult<?>) {
            com.wicket.okrapp.common.ro.OkrResult<?> result = (com.wicket.okrapp.common.ro.OkrResult<?>) ret;
            if (result.getMessage() != null && !result.getMessage().isEmpty()) {
                throw new BizException(result.getErrCode(), result.getMessage(), false);
            }
        }else if (ret instanceof com.wicket.okrcalc.common.ro.OkrResult<?>) {
            com.wicket.okrcalc.common.ro.OkrResult<?> result = (com.wicket.okrcalc.common.ro.OkrResult<?>) ret;
            if (result.getMessage() != null && !result.getMessage().isEmpty()) {
                throw new BizException(result.getErrCode(), result.getMessage(), false);
            }
        }else if (ret instanceof com.wicket.okrfinance.common.ro.OkrResult<?>) {
            com.wicket.okrfinance.common.ro.OkrResult<?> result = (com.wicket.okrfinance.common.ro.OkrResult<?>) ret;
            if (result.getMessage() != null && !result.getMessage().isEmpty()) {
                throw new BizException(result.getErrCode(), result.getMessage(), false);
            }
        }else if (ret instanceof com.wicket.okrdataassets.common.ro.OkrResult<?>) {
            com.wicket.okrdataassets.common.ro.OkrResult<?> result = (com.wicket.okrdataassets.common.ro.OkrResult<?>) ret;
            if (result.getMessage() != null && !result.getMessage().isEmpty()) {
                throw new BizException(result.getErrCode(), result.getMessage(), false);
            }
        }

    }

//    @Around("feignPointcut()")
//    public Object checkParam(ProceedingJoinPoint joinPoint) {
////        try {
////            Object[] args = joinPoint.getArgs();
////            if (args == null || args.length == 0) {
////                return joinPoint.proceed();
////            }
////            MetaDataHelper.putMetaData(args[0]);
////            MetaDataDto metaData = MetaDataHelper.getMetaData(args[0]);
////            if (metaData != null) {
////                if (metaData.getRequiredFieldList().size() == 0) {
////                    //如果没有必填字段,任何场景都是正常执行
////                    return joinPoint.proceed();
////                }
////                if (metaData.isAllRequired()) {
////                    if (!checkRequiredFieldList(args[0])) {
////                        //如果全都是必填字段，并且发现必填字段有空值,执行跳过
////                        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
////                        Class claszz = signature.getReturnType();
////                        return claszz.newInstance();
////                    } else {
////                        //如果全都是必填字段，并且发现必填字段无空值，正常执行
////                        return joinPoint.proceed();
////                    }
////                } else {
////                    if (!checkRequiredFieldList(args[0])) {
////                        //如果一部分是必填字段，一部分是非必填字段，并且发现必填字段有空值，抛异常
////                        throw new BizException("-1", "必填参数校验不通过", false);
////                    } else {
////                        //如果一部分是必填字段，一部分是非必填字段，并且发现必填字段无空值，正常执行
////                        return joinPoint.proceed();
////                    }
////                }
////            }
////
////        } catch (Exception e) {
////            e.printStackTrace();
////        } catch (Throwable throwable) {
////            throwable.printStackTrace();
////        }
////        return new Object();
//    }

    private boolean checkRequiredFieldList(Object param) {
        boolean bRet = true;
        try {
            Field[] fields = param.getClass().getDeclaredFields();
            MetaDataDto metaData = MetaDataHelper.getMetaData(param);
            for (Field field : fields) {
                Object value = field.get(param);
                if (value == null && metaData.getRequiredFieldList().contains(field)) {
                    bRet = false;
                    break;
                }
            }
        } catch (Exception e) {

        }
        return bRet;
    }
}
